#ifndef _UTILS_H
#define _UTILS_H

#include <sys/types.h>

#include <string>
#include <list>
#include <limits.h>

#ifndef ARRAY_SIZE
#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
#endif

#ifndef UID_MAX
# define UID_MAX	UINT_MAX
#endif
#ifndef GID_MAX
# define GID_MAX	UINT_MAX	
#endif

#ifndef UNUSED
#define UNUSED(x)	((void)(x))
#endif

#define CS(string)	((string).c_str())

namespace utils {

using namespace std;


// Note! Process state codes in Linux may change in future versions. The list of active state codes
//       can be found from the kernel sources by looking at the function get_task_state() in fs/proc/array.c.
enum KernelProcessState {		// From /proc/<PID>/stat (See man proc for more info)
	PROC_STATE_RUNNING,		// R - Running (busy)
	PROC_STATE_SLEEP,		// S - Sleeping in interruptible wait
	PROC_STATE_DISK_SLEEP,		// D - Waiting in uninterruptible disk sleep
	PROC_STATE_ZOMBIE,		// Z - Zombie state
	PROC_STATE_TRACED,		// t - Process is stopped (on a signal) or being traced/debugged
	PROC_STATE_PAGING,		// W - Process is paging (only used before linux 2.6.0)
	PROC_STATE_UNKNOWN,		// Unknown status (future Linux kerne versions may have additional states)
	PROC_STATE_TERMINATED,		// Nonexistent or terminated (/proc/<PID>/stat doesn't exist.
	PROC_STATE_STOPPED,		// T - Stopped on a signal
	PROC_STATE_DEAD,		// X - Dead (also x means dead)
	PROC_STATE_WAKEKILL,		// K - Wakekill
	PROC_STATE_WAKING,		// W - Waking (Linux 2.6.33 to 3.13 only)
	PROC_STATE_PARKED,		// P - Parked (Linux 3.9 to 3.13 only)
	PROC_STATE__LAST
// NOTE: PROC_STATE_TERMINATED and PROC_STATE_ZOMBIE mean that the process has terminated. The others
//       mean that the process is still alive. PROC_STATE_UNKNOWN is indication of internal error in 
//       getProcessSchedulingState() or a new scheduling state has been introduced in the kernel (however the
//       process still exists).
};


string fix_path(const string& path);

bool file_exists(const string& file, mode_t type, mode_t mode = 0);

#define REG_MASK	(1 << DT_REG)
#define DIR_MASK	(1 << DT_DIR)
#define LNK_MASK	(1 << DT_LNK)
#define CHR_MASK	(1 << DT_CHR)
#define BLK_MASK	(1 << DT_BLK)

typedef int (*find_cb_t)(const char *path, int type, void *arg);
int find(const dev_t dev, const char *path, int dts, find_cb_t func, void *arg);

int set_attrs(const string& path, uid_t uid, gid_t gid, mode_t fmode, mode_t dmode, const string& pkgid, const char *seinfo);

int sysexec(const string& exec);
int vasystem(const char *format, ...);
int copy_path(const string& from, const string& to, const string& file);
void rmrf(const string& path, bool recursive=true);
int mkdir(const char *pathname, uid_t uid, gid_t gid, mode_t mode);

string getProcessName(pid_t pid);
string getProcessLabel(pid_t pid);
string getProcessExec(pid_t pid);
uid_t getProcessUid(pid_t pid);
gid_t getProcessGid(pid_t pid);
int getProcessSchedulingState(pid_t pid);
long getProcessSize(pid_t pid, long *pss, long *uss);
void setOomAdj(pid_t pid, int adj);
void getMemInfo(long& total, long &free, long& buffers, long& cached, long& shmem, long& slab);

void strToLower(const string& str);
void do_log_dump(const void *ptr, int len);

// ----------------- DirReader -----------------------------

class DirReader {
	class DirEntry {
	public:
		DirEntry(const char *_name, ino_t _ino, unsigned char _type);
		bool isFile();
		bool isDir();
	public:
		string	name;
		ino_t ino;
		unsigned char type;
	};

public:
	string &getName();
	string getPath();
	unsigned char getType();
	int readDir(const char *_base);
	size_t size();
	void start();
	bool next();

public:
	string base;
	list<DirEntry> entries;
	list<DirEntry>::iterator it;
	bool hasSubDirs;
	bool started;
	DirEntry *entry;
};

class URI {
public:
	URI();
	URI(const string &uri);
	URI(const URI &uri);
	void operator=(const string &uri);
	void operator=(const URI &uri);
	bool isRelative();
	void prepandPath(const string &origin);
	string get();
	bool empty();
public:
	string		scheme;
	string		domain;
	string		path;
};

//char *sha1encode(const char *input);

} // namespace appman

#endif
